home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / answrbok / 8_5.lha / 8_5 / doscan.c < prev    next >
C/C++ Source or Header  |  1993-08-08  |  8KB  |  425 lines

  1. * Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
  2. * The C++ Answer Book */
  3. * Tony Hansen */
  4. * All rights reserved. */
  5. / _doscanf(): low level function for doing formatted
  6. / input, to be invoked by the v*scanf() family
  7. / of functions.
  8. include <extbuf.h>
  9. include <scanset.h>
  10. include <ctype.h>
  11. include <stdlib.h>
  12.  
  13. / get the next character on the input stream,
  14. / adding to charcnt and returning EOF on end-of-file.
  15. nline int nextc(istream *in, int &charcnt)
  16.  
  17.    char c;
  18.    return (!in->get(c)) ?
  19. EOF :
  20. (charcnt++, c);
  21.  
  22.  
  23. * Define a macro to decrement the fieldwidth    */
  24. * and add the character to the buffer.        */
  25. define addc()                    \
  26.    fieldwidth--, svbuf.add(c)
  27.  
  28. * Define a macro to decrement the fieldwidth,    */
  29. * add the character to the buffer and get the    */
  30. * next character.                */
  31. define Nextc()                    \
  32.    do { addc(); c = nextc(in, charcnt); } while (0)
  33.  
  34. * Define macros to use for assigning the    */
  35. * appropriate value to the appropriate pointer    */
  36. * type to be pulled off the stack based on the    */
  37. * booleans halfsize, longsize and suppress.    */
  38. * assign() checks for halfsize, then invokes    */
  39. * liassign() below.                */
  40. define assign(var, stype, itype, ltype)    \
  41.    if (halfsize)                \
  42. {                    \
  43. stype *p = va_arg(vl, stype*);        \
  44. *p = (stype)var;            \
  45. }                    \
  46.                     \
  47.    else                    \
  48. liassign(var, itype, ltype)
  49.  
  50. * This macro is invoked from assign() above    */
  51. * and for %f, which doesn't allow the halfsized*/
  52. * modifier. It checks for the booleans longsize*/
  53. * and suppress.                */
  54. define liassign(var, itype, ltype)        \
  55.    if (longsize)                \
  56. {                    \
  57. ltype *p = va_arg(vl, ltype*);        \
  58. *p = (ltype)var;            \
  59. }                    \
  60.                     \
  61.    else if (!suppress)                \
  62. {                    \
  63. itype *p = va_arg(vl, itype*);        \
  64. *p = (itype)var;            \
  65. }
  66.  
  67. * define a macro to check for an optional sign    */
  68. define checksign()                \
  69.    if ((fieldwidth > 0) &&            \
  70. ((c == '-') || (c == '+')))        \
  71. {                    \
  72. Nextc();                \
  73. }
  74.  
  75. * This macro will check for one or more    */
  76. * characters which have a certain         */
  77. * characteristic checked by the testprog, such */
  78. * as isdigit. If the sequence is missing, it    */
  79. * is an error and the macro will break out of    */
  80. * the switch statement.            */
  81. define checkfield(testprog)            \
  82.    if ((fieldwidth > 0) && testprog(c))    \
  83. do  {                    \
  84.     addc();                \
  85. } while ((fieldwidth > 0) &&        \
  86.     testprog(c = nextc(in, charcnt)));    \
  87.                     \
  88.    else                    \
  89. {                    \
  90. goodformat = 0;                \
  91. break;                    \
  92. }
  93.  
  94. * This macro works just like checkfield()    */
  95. * except that it is not an error for the    */
  96. * sequence to be missing.            */
  97. define checkoptfield(testprog)            \
  98.    for ( ; (fieldwidth > 0) && testprog(c);    \
  99.   c = nextc(in, charcnt))        \
  100. {                    \
  101.     addc();                \
  102. }
  103.  
  104. / the input function
  105. nt _doscanf(istream *in, const char *fmt, va_list vl)
  106.  
  107.    if (!fmt)
  108. return EOF;
  109.  
  110.    int charcnt = 0;
  111.    int fieldcnt = EOF;
  112.    int goodformat = 1;
  113.    int c = nextc(in, charcnt);
  114.    extarray svbuf;
  115.  
  116.    // loop through the format string
  117.    while (*fmt && (c != EOF) && goodformat)
  118. {
  119. switch (*fmt++)
  120.     {
  121.     // format specification
  122.     case '%':
  123.     {
  124.     // '*' means suppress assignment
  125.     int suppress = 0;
  126.     if (*fmt == '*')
  127.         {
  128.         suppress = 1;
  129.         fmt++;
  130.         }
  131.  
  132.     // check for a fieldwidth
  133.     int fieldwidth = -1;
  134.     if (isdigit(*fmt))
  135.         fieldwidth =
  136.         (int)strtol(fmt, (char**)&fmt, 10);
  137.  
  138.     // Check for size modifiers.
  139.     // Just skip past if assignment
  140.     // is being suppressed.
  141.     int halfsize = 0;
  142.     int longsize = 0;
  143.     switch (*fmt)
  144.         {
  145.         case 'h':
  146.         if (!suppress)
  147.             halfsize = 1;
  148.         fmt++;
  149.         break;
  150.  
  151.         case 'l':
  152.         if (!suppress)
  153.             longsize = 1;
  154.         fmt++;
  155.         break;
  156.         }
  157.  
  158.     // set the default field width
  159.     if (fieldwidth == -1)
  160.         fieldwidth = (*fmt == 'c') ?
  161.              1 : INT_MAX;
  162.  
  163.     // check for skipping white space
  164.     switch (*fmt)
  165.         { // these do not skip white space
  166.         case '%': case 'n':
  167.         case '[': case 'c':
  168.         break;
  169.  
  170.         default:
  171.         // loop until a non-white-space
  172.         // character is found
  173.         if (isspace(c))
  174.             do  {
  175.             c = nextc(in, charcnt);
  176.             } while (isspace(c));
  177.         break;
  178.         }
  179.  
  180.     // only return EOF if an error
  181.     // occurred before the first
  182.     // field specifier is reached
  183.     if (fieldcnt == EOF)
  184.         fieldcnt = 0;
  185.  
  186.     svbuf.reset();
  187.  
  188.     // check for assignment type
  189.     switch (*fmt)
  190.         {
  191.         // store the number of read chars
  192.         case 'n':
  193.         assign(charcnt, short, int, long);
  194.         break;
  195.  
  196.         // fill svbuf with an integer
  197.         // or an unsigned integer
  198.         case 'd':
  199.         case 'u':
  200.         {
  201.         checksign();
  202.         checkfield(isdigit);
  203.  
  204.         /* assign to a signed number */
  205.         if (*fmt == 'd')
  206.             {
  207.             long i =
  208.             strtol(svbuf.val(),
  209.                 0, 10);
  210.             assign(i, short, int, long);
  211.             }
  212.  
  213.         /* assign to an unsigned number */
  214.         else
  215.             {
  216.             unsigned long i =
  217.             strtoul(svbuf.val(),
  218.                 0, 10);
  219.             assign(i, unsigned short,
  220.             unsigned int,
  221.             unsigned long);
  222.             }
  223.  
  224.         fieldcnt++;
  225.         break;
  226.         }
  227.  
  228.         // fill svbuf with a C++ integer
  229.         case 'i':
  230.         {
  231.         checksign();
  232.  
  233.         // check for leading 0 or 0x
  234.         if ((fieldwidth > 0) &&
  235.             (c == '0'))
  236.             {
  237.             Nextc();
  238.  
  239.             if ((fieldwidth > 0) &&
  240.             ((c == 'x') ||
  241.              (c == 'X')))
  242.             {
  243.             Nextc();
  244.             checkfield(isxdigit);
  245.             }
  246.  
  247.             else
  248.             checkfield(isodigit);
  249.             }
  250.  
  251.         else
  252.             checkfield(isdigit);
  253.  
  254.         long i =
  255.             strtol(svbuf.val(), 0, 0);
  256.         assign(i, short, int, long);
  257.         fieldcnt++;
  258.         break;
  259.         }
  260.  
  261.         // fill svbuf with an octal integer
  262.         case 'o':
  263.         {
  264.         checksign();
  265.         checkfield(isodigit);
  266.  
  267.         unsigned long i =
  268.             strtoul(svbuf.val(), 0, 8);
  269.         assign(i, unsigned short,
  270.             unsigned int, unsigned long);
  271.         fieldcnt++;
  272.         break;
  273.         }
  274.  
  275.         // fill svbuf with a hex integer
  276.         case 'x': case 'X':
  277.         {
  278.         checksign();
  279.         checkfield(isxdigit);
  280.  
  281.         unsigned long i =
  282.             strtoul(svbuf.val(), 0, 16);
  283.         assign(i, unsigned short,
  284.             unsigned int, unsigned long);
  285.         fieldcnt++;
  286.         break;
  287.         }
  288.  
  289.         // Read in a floating point number
  290.         case 'e': case 'E':
  291.         case 'g': case 'G':
  292.         case 'f':
  293.         {
  294.         checksign();
  295.         checkoptfield(isdigit);
  296.  
  297.         if ((fieldwidth > 0) &&
  298.             (c == '.'))
  299.             {
  300.             Nextc();
  301.             checkoptfield(isdigit);
  302.             }
  303.  
  304.         if ((fieldwidth > 0) &&
  305.             ((c == 'e') || (c == 'E')))
  306.             {
  307.             Nextc();
  308.             checksign();
  309.             checkfield(isdigit);
  310.             }
  311.  
  312.         double i =
  313.             strtod(svbuf.val(), 0);
  314.         liassign(i, float, double);
  315.         fieldcnt++;
  316.         break;
  317.         }
  318.  
  319.         // Read up to fieldwidth characters
  320.         // (minimum of 1) which match the
  321.         // scanset. Add a null character at
  322.         // the end of the string.
  323.         case '[':
  324.         {
  325.         char *p;
  326.         if (c == EOF)
  327.             break;
  328.         if (!suppress)
  329.             p = va_arg(vl, char*);
  330.  
  331.         scanset s(fmt, &fmt);
  332.         for ( ; (fieldwidth-- > 0) &&
  333.             s.match(c) ;
  334.               c = nextc(in, charcnt))
  335.             if (!suppress)
  336.                 *p++ = c;
  337.  
  338.         if (!suppress)
  339.             *p = '\0';
  340.         fieldcnt++;
  341.         break;
  342.         }
  343.  
  344.         // Read fieldwidth characters.
  345.         // Do NOT add a null character after.
  346.         case 'c':
  347.         {
  348.         char *p;
  349.         if (c == EOF)
  350.             break;
  351.         if (!suppress)
  352.             p = va_arg(vl, char*);
  353.  
  354.         for ( ; (fieldwidth-- > 0) &&
  355.             (c != EOF) ;
  356.               c = nextc(in, charcnt))
  357.             if (!suppress)
  358.             *p++ = c;
  359.  
  360.         fieldcnt++;
  361.         break;
  362.         }
  363.  
  364.         // Read a string terminated by
  365.         // white-space. Add a null character
  366.         // at the end of the string.
  367.         case 's':
  368.         {
  369.         char *p;
  370.         if (c == EOF)
  371.             break;
  372.         if (!suppress)
  373.             p = va_arg(vl, char*);
  374.  
  375.         for ( ; (fieldwidth-- > 0) &&
  376.             !isspace(c) ;
  377.               c = nextc(in, charcnt))
  378.             if (!suppress)
  379.             *p++ = c;
  380.  
  381.         if (!suppress)
  382.             *p = '\0';
  383.         fieldcnt++;
  384.         break;
  385.         }
  386.  
  387.         // match a single %
  388.         case '%':
  389.         if (c == '%')
  390.             c = nextc(in, charcnt);
  391.  
  392.         else
  393.             goodformat = 0;
  394.         break;
  395.         }
  396.     break;
  397.     }
  398.  
  399.     case ' ': // match white-space
  400.     case '\t': // match white-space
  401.     if (isspace(c))
  402.         do  {
  403.         svbuf.add(c);
  404.         } while
  405.         (isspace(c = nextc(in, charcnt)));
  406.  
  407.     else
  408.         goodformat = 0;
  409.     break;
  410.  
  411.     default: // match character
  412.     if (c == fmt[-1])
  413.         c = nextc(in, charcnt);
  414.  
  415.     else
  416.         goodformat = 0;
  417.     break;
  418.     }
  419. }
  420.  
  421.    if (c != EOF)
  422. in->putback(c);
  423.    return fieldcnt;
  424.  
  425.